"""
safeint module
"""
from inspect import getouterframes,currentframe
#from sypy import type_factory

class _safeint_factory__(type):
	""" 
	safeint metaclass, used to programatically inject l,r,i operators in the new type class
	so we can check the operation result as a safeint  
	"""
	#BOF __new__
	def __new__(cls,name,bases,dct):
		instance = type.__new__(cls,name,bases,dct)
		#print "safeint_factory: type=%r"%name
		if 'safeint' == name:  return instance
		def build_operator(op):
			def f_op(self,other): 
				if not isinstance(other,int): raise ValueError("non-int type operand. apply int() to force")
				return safeint.__new__(self.__class__,getattr(super(safeint,self),'__' + op + '__')(other))
			return f_op
		
		for op in ['add','sub','mul','div','truediv','floordiv','mod','pow','shift','and','or','xor']:
			setattr(instance,'__' + op + '__',build_operator(op))
			setattr(instance,'__' + 'i' + op + '__',build_operator(op))
			setattr(instance,'__' + 'r' + op + '__',build_operator(op))
			setattr(instance,'__' + 'l' + op + '__',build_operator(op))
		#[map(lambda op: setattr(instance,'__'+  op_type + op,build_operator(op)), \
		#	['add__','sub__','mul__','div__','truediv__','floordiv__','mod__','pow__','lshift__',
		#	 'rshift__','and__','or__','xor__']) for op_type in ['i','r','l','']] 
		return instance
	#EOF __new__

class safeint(int):
	__metaclass__ = _safeint_factory__
	#BOF __new__	
	def __new__(cls,v_=None):
		if v_ is None:
			try:
				v = getattr(cls,'vdef')
			except AttributeError:
				raise ArithmeticError("no value specified for this int and no default value found in class definition")
		else:
			if not isinstance(v_,int): raise ValueError("non-int type operand. apply int() to force")
			v = v_
		try:
			vmin = getattr(cls,'vmin')
			assert v >= vmin
		except AttributeError:
			pass
		except AssertionError:
			raise OverflowError
		try:
			vmax = getattr(cls,'vmax')
			#print "failing assert: v=%r,vmax=%r class=%r"%(v,vmax,cls)
			assert v <= vmax
		except AttributeError:
			pass
		except AssertionError:
			raise OverflowError
		return int.__new__(cls,v)
	#EOF __new__
	@property
	def value(self):
		return self
	@value.setter
	def value(self,v):
		raise TypeError



def safeint_factory(*args,**kw):
	"""
	USE: inject a new safeint type into caller's frame globals() (bah!)
	WHY: all-in-one type_definition+"type_import"
	CAUTION: dangerous. for programmatical safeint types definitions you may just use type() when needed
	CALLSIG: safeint_factory(type_name,vmin=min_allowed,vmax=max_allowed,vdef=default_value)
	EXAMPLE: 
		from safeint import safeint_factory
		safeint_factory('IPV4_BYTE',vmin=0,vmax=255)
		ipbytes = map(lambda ipbyte: IPV4_BYTE(int(ipbyte)), '1.2.3.4'.split('.'))
		for b in ipbytes:
			print b,type(b)
		>>> 1 <class '__main__.IPV4_BYTE'>
		>>> 2 <class '__main__.IPV4_BYTE'>
		>>> 3 <class '__main__.IPV4_BYTE'>
		>>> 4 <class '__main__.IPV4_BYTE'>

	
	
	"""
	getouterframes(currentframe())[1][0].f_globals[args[0]] = type(args[0],(safeint,),kw)




if '__main__' == __name__:
	safeint_factory('ttl',vmin=0,vmax=2147483647,vdef=14400)
	safeint_factory('serial',vmin=12,vmax=15,vdef=13)
	safeint_factory('IPV4_BYTE',vmin=0,vmax=255)
	x = ttl(15800)
	print x,type(x)
	print x.value
	#x*=15800
	print x,type(x)
	x = ttl()
	print x.value
	x+=1
	print type(x)
	print x
	x+=2
	print type(x)
	print x.__coerce__(2.4)
	b=x+4
	#x+=66666666666666
	print b,type(b)
	b = 4 + x
	print b,type(b)
	ipbytes = map(lambda ipbyte: IPV4_BYTE(int(ipbyte)), '1.2.3.44'.split('.'))
	for b in ipbytes:
		print b,type(b)
	#x.value = 34
	#x=ttl(-1)
	#print x
	#safeint_factory('serial',vmin=12,vmax=15,vdef=13)
	#x = serial()
	#print x
	#x+=1
	#x = serial(14)
	#print x
	#x = serial(23)
	#print x
